#include "stdafx.h"
#include "TextonGroup.h"

#define PYRAMID_SCALE 0.7

bool operator<(const Texton& t1,const Texton& t2) {
	if(t1.x < t2.x) {
		return true;
	} else {
		if(t1.y < t2.y) {
			return true;
		} else {
			return true;
		}
	}
}

void TextonGroup::AddTexton(Texton* t) {
	//create a "false" instance (force shallow copy c'tor) and only 
	//change the width and height to be the "real" width and height
	Texton tt = *(t);
	Texton* texton = &tt;
	double lvlScale = pow((1 / PYRAMID_SCALE), t->levelFound);
	tt.x = (int)(tt.x * lvlScale);
	tt.y = (int)(tt.y * lvlScale);
	tt.width = (int)(tt.width * lvlScale);
	tt.height = (int)(tt.height * lvlScale);

	if (m_vecTextons.empty())
	{
		x = texton->x;
		y = texton->y;
		width = texton->width;
		height = texton->height;

		//TODO: Review this assumption
		levelFound = texton->levelFound;
		detectorId = texton->detectorId;
	}
	else
	{
		// Recalculate external group bounds

		if (texton->x < x) {
			width = width + (x - texton->x);
			x = texton->x;
		}
		if (texton->x + texton->width > x + width) {
			width = (texton->x + width) - x;
		}
		if (texton->y < y) {
			height = height + (y - texton->y);
			y = texton->y;
		}
		if (texton->y + texton->height > y + height) {
			height = (texton->y + height) - y;
		}
	}

	m_vecTextons.push_back(t);
}

void TextonGroup::UpdateImage(IplImage* orig)
{
	if (m_vecTextons.empty()) return;

	//if (m_vecTextons.size() == 1) {
	//	// Special case where there is only one texton in the group
	//	return;
	//}

	if (m_pTextonImage != NULL)
	{
		cvResetImageROI(m_pTextonImage);
		cvReleaseImage(&m_pTextonImage);
	}

	// Create new image with the size of combined, use first texton as reference
	// and assume (safely) that all textons have same depth and number of channels
	m_pTextonImage = cvCreateImage(
						cvSize(width, height),
						m_vecTextons[0]->GetImage()->depth,
		                m_vecTextons[0]->GetImage()->nChannels);
	cvZero(m_pTextonImage);

	IplImage* immm = orig;

	for (unsigned int i = 0; i < m_vecTextons.size(); i++)
	{
		Texton* t = m_vecTextons[i];

		//use a temporar texton to use the "real" size
		Texton tt = *(t);
		double lvlScale = pow((1 / PYRAMID_SCALE), t->levelFound);
		tt.x = (int)(tt.x * lvlScale);
		tt.y = (int)(tt.y * lvlScale);
		tt.width = (int)(tt.width * lvlScale);
		tt.height = (int)(tt.height * lvlScale);
		Texton* texton = &tt;

		//assume this group's level is the texton's level
		//double thisLvlScale = lvlScale;

		//int thisX = this->x * thisLvlScale;
		//int thisY = this->y * thisLvlScale;

		int xDiff = texton->x - this->x;
		int yDiff = texton->y - this->y;

		// Copy all pixels of the texton onto the image
		for(int _x = 0; _x < texton->width; _x++) {
			for(int _y = 0; _y < texton->height; _y++) {
				if(xDiff + _x >= m_pTextonImage->width || yDiff + _y >= m_pTextonImage->height
					|| texton->x + _x >= immm->width || texton->y + _y >= immm->height)
				{
					//error
					printf("Error");
					continue;
				}
				CvScalar col = cvGet2D(immm, texton->y + _y, texton->x + _x);
				cvSet2D(m_pTextonImage, 
					yDiff + _y, 
					xDiff + _x, 
					col
					);
			}
		}

		//cvResetImageROI(texton->GetImage());
		//cvResetImageROI(m_pTextonImage);
	}
	/*
	cvNamedWindow("Real Texton");
    cvShowImage("Real Texton",m_pTextonImage);
	cvWaitKey();
	*/
}

void TextonGroup::Save(const string& strPath )
{
	if (m_pTextonImage == NULL)
	{
		printf("Could not save texton, image is null\n");
		return;
	}
	std::string filePath;
	std::stringstream out;
	out << strPath;
	out << "group";
	out << detectorId;
	out << "_";
	out << levelFound;
	out << "_";
	out << textonId;

	out << ".bmp";

	filePath = out.str();

	cvSaveImage(filePath.c_str(), m_pTextonImage);
}

void TextonGroup::MarkTextons(IplImage* inputImage, CvScalar color)
{
	for (unsigned int i = 0; i < m_vecTextons.size(); i++)
	{
		m_vecTextons[i]->MarkTexton(inputImage, color);
	}
}